﻿using Microsoft.EntityFrameworkCore;
using Services.Activity.Domain;
using Services.Activity.Domain.Entities;
using Services.Initial.PublicProject.PublicClass.ExtensionException;
using System.Linq;


namespace Services.Activity.Infrastructure;
public class ActivityRepository(ActivityDbContext activityDbContext) : IActivityRepository
{
    private readonly ActivityDbContext dbContext = activityDbContext;

    public async Task<bool> ActivityAddVolunteerAsync(long activityId, long volunteerId)
    {
        var activity = (await this.dbContext.Activities.Select(x => new { x.ActivityId, x.Volunteers }).FirstOrDefaultAsync(x => x.ActivityId == activityId)) ?? throw new ExceptionWithStatus(System.Net.HttpStatusCode.NotFound, "活动的索引无效，请重新确认");
        if (activity.Volunteers.Any(x => x.VolunteerId == volunteerId))
        {
            throw new ExceptionWithStatus(System.Net.HttpStatusCode.BadRequest, "志愿者已经参加了这个活动");
        }
        var activityVolunteer = ActivityVolunteer.Create(activityId, volunteerId);
        activity.Volunteers.Add(activityVolunteer);
        this.dbContext.Entry(activityVolunteer).State = EntityState.Added;
        return await this.dbContext.SaveChangesAsync() > 0;
    }

    public async Task<VoluntaryActivity> AddAsync(VoluntaryActivity voluntaryActivity)
    {
        //不允许同名，同一个组织者不允许出先同名的志愿活动
        var OrganizerRes = this.dbContext.Activities.Where(x => x.OrganizerId == voluntaryActivity.OrganizerId).ToList();
        if (OrganizerRes.Any(x => x.ActivityName == voluntaryActivity.ActivityName))
        {
            throw new ExceptionWithStatus(System.Net.HttpStatusCode.BadRequest, "同一个志愿者不允许出现同名称的志愿活动");
        }
        // 判断没有存在同名的活动，现在去插入数据库
        this.dbContext.Activities.Add(voluntaryActivity);
        await this.dbContext.SaveChangesAsync();
        return voluntaryActivity;
    }

    public async Task<List<long>> FilterActivityAsync(List<Func<VoluntaryActivity, bool>> filters)
    {
        return await Task.Run(() =>
        {
            var query = this.dbContext.Activities.AsNoTracking().AsQueryable();
            foreach (var func in filters)
            {
                query = query.Where(func).AsQueryable();
            }
            return (query.ToList()).Select(x => x.ActivityId).ToList();
        });

    }

    public async Task<List<VoluntaryActivity>> GetActivitiesDetailAsync(List<long> id)
    {
        var result = await this.dbContext.Activities.Where(x => id.Any(y => y == x.ActivityId)).ToListAsync();
        if (result.Count == 0) { throw new ExceptionWithStatus(System.Net.HttpStatusCode.NotFound, "查找未知的活动详情，查找失败"); }
        return result;
    }

    public async Task<ActivityVolunteer> GetActivityVolunteerAsync(long activityId, long volunteerId)
    {
        var activity = await this.dbContext.Activities.FirstOrDefaultAsync(x => x.ActivityId == activityId) ?? throw new ExceptionWithStatus(System.Net.HttpStatusCode.NotFound, "活动无效，请重新确认");
        var activityVolunteer = activity.Volunteers.FirstOrDefault(x => x.VolunteerId == volunteerId) ?? throw new ExceptionWithStatus(System.Net.HttpStatusCode.NotFound, "志愿者未参加该活动，请重新确认");
        return activityVolunteer;
    }

    public Task<List<VoluntaryActivity>> GetOrganizerActivityAsync(long userId)
    {
        return this.dbContext.Activities.AsNoTracking().Where(x => x.OrganizerId == userId).ToListAsync();
    }

    public async Task<List<VoluntaryActivity>> GetVolunteerActivityListAsync(long userId)
    {
        var result = await this.dbContext.Activities.AsNoTracking().Include(x => x.Volunteers).Where(x => x.Volunteers.Any(x => x.VolunteerId == userId)).ToListAsync();
        //if (result.Count == 0)
        //{
        //    throw new ExceptionWithStatus(System.Net.HttpStatusCode.BadRequest, "志愿者还未参加任何活动");
        //}

        return result;
    }

    public async Task<bool> SignInVolunteerAsync(ActivityVolunteer activityVolunteer)
    {
        activityVolunteer.SignIn();
        this.dbContext.Entry(activityVolunteer).State = EntityState.Modified;
        return await this.dbContext.SaveChangesAsync() > 0;
    }
}